#ifndef	__BFX__REF_XMLDOCUMENT_H__
#define	__BFX__REF_XMLDOCUMENT_H__

#include "REFXMLNode.h"
#include "REFXMLLinkedNode.h"
#include "REFXMLElement.h"
#include "REFXMLAttribute.h"
#include "REFXMLText.h"
#include "REFXMLComment.h"
#include "REFXMLCDataSection.h"
#include "REFXMLProcessingInstruction.h"
#include "REFXMLEntityReference.h"
#include "REFXMLDeclaration.h"
#include "REFXMLDocumentType.h"
#include "REFXMLEntity.h"
#include "REFXMLNotation.h"

#include "REFXMLNodeList.h"
#include "REFXMLNodeMap.h"
#include "REFXMLAttributeMap.h"

namespace BFX
{

//////////////////////////////////////////////////////////////////////////////

typedef REFWrapper<Array<REFXMLElement*> > REFXMLElementWeakRefArray;
typedef REFWrapper<HashMap<UniString, REF<REFXMLElementWeakRefArray> > > REFXMLElementIdMap;
#ifdef	BFX_DLL_BUILD
template class BFX_API REF<REFXMLElementIdMap>;
#endif
typedef	REFWrapper<HashMap<REF<REFXMLName>, REF<REFXMLName> > >	REFXMLElementIDAttrDeclMap;

//////////////////////////////////////////////////////////////////////////////

// Represents an entire document. An xml document contains XML data.
class BFX_API REFXMLDocument : public REFXMLNode
{
	friend class REFXMLNode;
	friend class REFXMLText;
	friend class REFXMLElement;
	friend class REFXMLNameTable;
	friend class REFXMLLoader;
	friend class REFXMLComment;
	friend class REFXMLCDataSection;
	friend class REFXMLAttribute;
	friend class REFXMLEntity;
	friend class REFXMLEntityReference;
	friend class REFXMLNotation;
	friend class REFXMLElementList;
	friend class REFXMLAttributeMap;

public:
	REFXMLDocument();
	virtual ~REFXMLDocument();

	// Gets the type of the current node.
	virtual XMLNodeType GetNodeType() const;
	virtual REFXMLNode* GetParentNode() const;
	// Gets the name of the node.
	virtual UniString GetName() const;
	// Gets the name of the current node without the namespace prefix.
	virtual UniString GetLocalName() const;
	virtual REFXMLDocument* GetOwnerDocument() const;

	// Gets or sets the markup representing just the children of this node.
	virtual UniString GetInnerXml() const;
	virtual void SetInnerXml(const UniString& str);

	virtual UniString GetBaseURI() const;

	virtual void WriteTo(REFXMLWriter* w) const;
	virtual void WriteContentTo(REFXMLWriter* w) const;

	REFXMLElement* GetDocumentElement() const;

	// Gets the node for the DOCTYPE declaration.
	REFXMLDocumentType* GetDocumentType() const;

	// Creates an XmlAttribute with the specified name.
	REFXMLAttribute* CreateAttribute(const UniString& strName);
	// Creates an element with the specified name.
	REFXMLElement* CreateElement(const UniString& strName);
	// Creates an XmlText with the specified text.
	REFXMLText* CreateTextNode(const UniString& strText);
	// Creates an XmlComment containing the specified data.
	REFXMLCDataSection* CreateCDataSection(const UniString& strData);
	// Creates an XmlComment containing the specified data.
	REFXMLComment* CreateComment(const UniString& strData);
	
	// Returns a new XmlDocumentType object.
	REFXMLDocumentType* CreateDocumentType(const UniString& strName, const UniString& strPublicId, const UniString& strSystemId, const UniString& strInternalSubset);

	// Creates a XmlProcessingInstruction with the specified name and data strings.
	REFXMLProcessingInstruction* CreateProcessingInstruction(const UniString& strTarget, const UniString& strData);
	// Creates a XmlDeclaration node with the specified values.
	REFXMLDeclaration* CreateXmlDeclaration(const UniString& strVersion, const UniString& strEncoding, const UniString& strStandalone);

	// Creates an XmlEntityReference with the specified name.
	REFXMLEntityReference* CreateEntityReference(const UniString& strName);

	// Saves the XML document to the specified XmlWriter.
	// 
	//Saves out the file with xmldeclaration which has encoding value equal to
	//that of textwriter's encoding
	void Save(REFXMLWriter* w);
	// Loads the XML document from the specified xmlreader.
	bool Load(REFXMLReader* r);

	// Loads the XML document from the specified string.
	bool LoadXml(const UniString& strXml);

	// Returns an XmlNodeList containing
	// a list of all descendant elements that match the specified name.
	REFXMLNodeList* GetElementsByTagName(const UniString& strName) const;
	// Returns the XmlElement with the specified ID.
	REFXMLElement* GetElementById(const UniString& strElementId) const;


	// DOM Level 2
	// Creates a XmlAttribute with the specified Prefix, LocalName, and NamespaceURI.
	REFXMLAttribute* CreateAttribute(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI);
	REFXMLAttribute* CreateDefaultAttribute(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI);
	// Creates a XmlDocument with the specified Prefix, LocalName, and NamespaceURI.
	REFXMLElement* CreateElement(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI);

	// Returns a XmlNodeList containing
	// a list of all descendant elements that match the specified name.
	REFXMLNodeList* GetElementsByTagName(const UniString& strLocalName, const UniString& strNamespaceURI) const;

	const XMLErrorContext& GetLastError() const;
	bool IsErrorOccurred() const;

protected:
	virtual bool IsContainer() const;
	virtual bool IsValidChildType(XMLNodeType type) const;

	virtual REFXMLLinkedNode* GetFirstNode() const;
	virtual void SetFirstNode(REFXMLLinkedNode* pNode);

	virtual REFXMLLinkedNode* GetLastNode() const;
	virtual void SetLastNode(REFXMLLinkedNode* pNode);

	void SetBaseURI(const UniString& strBaseURI);

	REFXMLNodeMap* GetEntities() const;
	void SetEntities(REFXMLNodeMap* pEntities);

	REFXMLSchemaInfo* GetDtdSchemaInfo() const;
	void SetDtdSchemaInfo(REFXMLSchemaInfo* pDtdSchemaInfo);

	REFXMLName* AddXmlName(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI);
	REFXMLName* AddAttrXmlName(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI);
	REFXMLName* GetXmlName(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNamespaceURI);

	bool AddElementIdInfo(REFXMLName* pEleName, REFXMLName* pAttrName);
	REFXMLName* GetElementIdInfo(REFXMLName* pEleName);
	void AddElementWithId(const UniString& strId, REFXMLElement* pElem);
	void RemoveElementWithId(const UniString& strId, REFXMLElement* pElem);
	REFXMLElement* GetElement(REFXMLElementWeakRefArray* pElementList, REFXMLElement* pElem);

	void SetDefaultNamespace(const UniString& strPrefix, const UniString& strLocalName, OUT UniString& strNamespaceURI);
	// Gets the xml name table associated with this implementation.
	REFNameTable* GetNameTable() const;

	UniString GetStandalone() const;
	REFXMLDeclaration* GetDeclaration() const;
	REFXMLEntity* GetEntityNode(const UniString& strName);

	//the function is provided only at Load time to speed up Load process
	virtual REFXMLNode* AppendChildForLoad(REFXMLNode* pNewChild, REFXMLDocument* pDoc);

	// The function such through schema info to find out if there exists a default attribute with passed in names in the passed in element
	// If so, return the newly created default attribute (with children tree);
	// Otherwise, return null.
	REFXMLAttribute* GetDefaultAttribute(REFXMLElement* pElem, const UniString& strAttrPrefix, const UniString& strAttrLocalname, const UniString& strAttrNamespaceURI);
	REFXMLSchemaElementDecl* GetSchemaElementDecl(REFXMLElement* pElem);
	// Will be used by AddDeafulatAttributes() and GetDefaultAttribute() methods
	REFXMLAttribute* PrepareDefaultAttribute(REFXMLSchemaAttDef* pAttdef, const UniString& strAttrPrefix, const UniString& strAttrLocalname, const UniString& strAttrNamespaceURI);

	void NotifyChanged();
	int GetChangeCount() const;

protected:
	REFXMLNameTable*	m_pDomNameTable;
	REFNameTable*		m_pNameTable;

	REF<REFXMLNodeMap>	m_pEntities;

	REF<REFXMLLinkedNode>	m_pFirstChild;
	REFXMLLinkedNode*	m_pLastChild;

	bool		m_bPreserveWhitespace;
	bool		m_bIsLoading;

	bool		m_bCDataNodesPresent;
	bool		m_bEntRefNodesPresent;

	UniString	m_strBaseURI;
	REFXMLSchemaInfo*	m_pSchemaInfo;

	REF<REFXMLElementIdMap>		m_pElementIdMap;
	REFXMLElementIDAttrDeclMap*	m_pElementIDAttrDecl;	//key: id; object: the ArrayList of the elements that have the same id (connected or disconnected)

	// special name strings for
	UniString	m_strEmpty;
	UniString	m_strDocumentName;
	UniString	m_strDocumentFragmentName;
	UniString	m_strCommentName;
	UniString	m_strTextName;
	UniString	m_strCDataSectionName;
	UniString	m_strEntityName;
	UniString	m_strID;
	UniString	m_strNonSignificantWhitespaceName;
	UniString	m_strSignificantWhitespaceName;
	UniString	m_strXmlns;
	UniString	m_strXml;
	UniString	m_strSpace;
	UniString	m_strLang;
	UniString	m_strReservedXmlns;
	UniString	m_strReservedXml;

	Mutex	m_docMutex;

	mutable	int	m_nChangeCount;
	XMLErrorContext	m_errorContext;	// the error context only uses for parse xml.
};

}	//	namespace BFX

#endif	//	__BFX__REF_XMLDOCUMENT_H__
